package pl.elka.pszt.model;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import pl.elka.pszt.model.argument.Argument;
import pl.elka.pszt.model.argument.ArgumentHelper;
import pl.elka.pszt.model.literal.Literal;
import pl.elka.pszt.model.literal.LiteralHelper;

/**
 * Reprezentuje baze wiedzy, skladajacej sie z elementow wiedzy w postaci
 * klauzul koniunkcyjno-implikacyjnych lub tez faktow.
 * 
 * @author Andrzej Makarewicz
 * 
 */
public class Knowledge {
	
	/**
	 * Mapowanie id predykatu na liste elementow wiedzy ktorych konkluzja ma
	 * literal z tym predykatem
	 */
	private final Map<Integer, List<KnowledgeElement>> elements = new HashMap<Integer, List<KnowledgeElement>>();
	
	private final KnowledgeLoader loader;
	
	public Knowledge(LiteralHelper literalHelper, ArgumentHelper argumentHelper) {
		this.loader = new KnowledgeLoader(this, literalHelper, argumentHelper);
	}
	
	/**
	 * 
	 * @param literal
	 *            literal do przypasowania
	 * @param arguments
	 *            argumenty podstawione w literale
	 * @return lista elementow wiedzy ktorych klauzule pasuja do literalu
	 */
	public List<KnowledgeElement> getMatchingElements(Literal literal) {
		return getMatchingElements(literal, literal.getArguments());
	}
	
	/**
	 * 
	 * @param assigned
	 *            przypisanie literalu
	 * @return lista elementow wiedzy ktorych klauzule pasuja do przypisania
	 *         literalu
	 */
	public List<KnowledgeElement> getMatchingElements(Assigned assigned) {
		return getMatchingElements(assigned.getLiteral(), assigned.getArguments());
	}
	
	/**
	 * 
	 * @param literal
	 *            literal do przypasowania
	 * @param arguments
	 *            argumenty podstawione w literale
	 * @return lista elementow wiedzy ktorych klauzule pasuja do literalu o
	 *         danych argumentach
	 */
	private List<KnowledgeElement> getMatchingElements(Literal literal, List<? extends Argument> arguments) {
		List<KnowledgeElement> elementsList = elements.get(literal.getPredicat().getId());
		if (elementsList == null || elementsList.isEmpty()) return null;
		
		List<KnowledgeElement> result = new ArrayList<KnowledgeElement>();
		for (KnowledgeElement element : elementsList) {
			if (element.getConclusion().matches(literal, arguments)) result.add(element);
		}
		
		return result;
	}
	
	/**
	 * Dodaje do bazy wiedzy mapujac zgodnie z id predykatu.
	 * 
	 * @param element
	 *            dodawany do bazy wiedzy.
	 */
	public void addElement(KnowledgeElement element) {
		// Log.o(TAG, Log.getCurrentMethodName() + " " + element.toString());
		
		int id = element.getConclusion().getPredicat().getId();
		List<KnowledgeElement> elementsList = elements.get(id);
		if (elementsList == null) {
			elementsList = new ArrayList<KnowledgeElement>();
			elements.put(id, elementsList);
		}
		elementsList.add(element);
	}
	
	/**
	 * Czysci baze wiedzy.
	 */
	public void clear() {
		elements.clear();
	}
	
	/***************** LOADER *****************/
	
	public boolean loadFromResource(String fileName) {
		return loader.loadFromResource(fileName);
	}
	
	public boolean loadFromFile(File file) {
		return loader.loadFromFile(file);
	}
}
